﻿using Furion.DatabaseAccessor;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using HiSport.Application.HiSportService.Bas.BasRuleManagement.BillingRules.Dtos;
using HiSport.Application.HiSportService.Bas.BasSiteManagement.Service;
using HiSport.Core;
using HiSport.Core.Entity;
using HiSport.Core;
using HiSport.Core.Util;
using Mapster;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Yitter.IdGenerator;
using HiSport.Core.Entity.HiSportEntity.Bas;

namespace HiSport.Application.HiSportService.Bas.BasRuleManagement.BillingRules.Service
{

    //[ApiDescriptionSettings("规则管理", Tag = "计费规则", SplitCamelCase = false)]
    [ApiDescriptionSettings("VenueSetup", Tag = "BillingRules", SplitCamelCase = false)]
    public class BillingRulesService : ITransient, IBillingRulesService, IDynamicApiController
    {
        private readonly SqlSugarRepository<BasBillingRule> _basBillingRule;
        private readonly SqlSugarRepository<BasBillingRuleInfo> _basBillingRuleInfo;
        private readonly SqlSugarRepository<BasBillingRuleInfoMember> _basBillingRuleInfoMember;
        private readonly SqlSugarRepository<BasSiteBillingRule> _basSiteBillingRule;
        private readonly SqlSugarRepository<BasVenues> _basVenues;
        private readonly SqlSugarRepository<BasSiteType> _basSiteType;


        public BillingRulesService(SqlSugarRepository<BasBillingRule> basBillingRule,
            SqlSugarRepository<BasBillingRuleInfo> basBillingRuleInfo,
            SqlSugarRepository<BasBillingRuleInfoMember> basBillingRuleInfoMember,
            SqlSugarRepository<BasSiteBillingRule> basSiteBillingRule,
            SqlSugarRepository<BasVenues> basVenues,
             SqlSugarRepository<BasSiteType> basSiteType)
        {
            _basBillingRule = basBillingRule;
            _basBillingRuleInfo = basBillingRuleInfo;
            _basBillingRuleInfoMember = basBillingRuleInfoMember;
            _basSiteBillingRule = basSiteBillingRule;
            _basVenues = basVenues;
            _basSiteType = basSiteType;
        }

        #region 计费规则

        /// <summary>
        /// 分页
        /// </summary>
        /// <param name="indexDto"></param>
        /// <returns></returns>
        [ApiDescriptionSettings(Name = "Page"), HttpPost]
        [DisplayName("分页")]
        public async Task<SqlSugarPagedList<BillingRuleDto>> Page(BillingRulePageDto inputDto)
        {
            //获取组织下的 球场

            var venueIds = _basVenues.AsQueryable().Select(x => x.Id).ToList();

            //查询计费规则
            var result = await _basBillingRule.AsQueryable()
                 .LeftJoin<BasVenues>((u, a) => u.VenueId == a.Id)
                .WhereIF(!string.IsNullOrWhiteSpace(inputDto.RuleName), (u, a) => u.RuleName.Contains(inputDto.RuleName.Trim()))
                .WhereIF(inputDto.Status.HasValue, (u, a) => u.Status == inputDto.Status)
                .Where((u, a) => venueIds.Contains(u.VenueId))
                .OrderBy((u, a) => u.Sort)
                .Select((u, a) => new BillingRuleDto()
                {
                    Id = u.Id.SelectAll(),
                    VenueName=a.VenuesName
                })
                .ToPagedListAsync(inputDto.Page, inputDto.PageSize);

            var ids = result.Items.Select(x => x.Id).ToList();

            //查询计费规则的详情
            var billingRuleInfo = await _basBillingRuleInfo.AsQueryable().Where(x => ids.Contains(x.BillingRuleId)).ToListAsync();


            //查询计费的规则详情的会员计费规则

            var billingRuleInfoIds = billingRuleInfo.Select(x => x.Id).ToList();

            var billingRuleInfoMember =await _basBillingRuleInfoMember.AsQueryable()
                .Where(x => billingRuleInfoIds.Contains(x.BasBillingRuleInfoId)).ToListAsync(); 
            foreach (var item in result.Items)
            {
                var res = billingRuleInfo
                   .Where(x => x.BillingRuleId == item.Id)
                   .Select(x => new BillingRuleInfoDto()
                   {
                       Id = x.Id,
                       EndTime = x.EndTime,
                       StartTime = x.StartTime,
                       BillingRuleId = x.BillingRuleId,
                       MemberPriceType = x.MemberPriceType,
                       MemberUnifyPrice = x.MemberUnifyPrice,
                       Price = x.Price,
                       MemberPrice= billingRuleInfoMember.Select(x => new VIPPronPrice()
                       {
                           GradeId = x.GradeId,
                           Price=x.Price,
                       }).ToList(),
                   })
                   .ToList();

                item.BillingRuleInfos = res;
            }

            return result;
        }

        

        /// <summary>
        /// 创建计费规则
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [UnitOfWork]
        [DisplayName("创建计费规则")]
        [ApiDescriptionSettings(Name = "Create"), HttpPost]
        public async Task<bool> Create(BillingRuleCreateOrUpDateDto inputDto)
        {
            //时间验证
            CheckBillingRuleTime(inputDto.BillingRuleInfos);

            //添加主订单
            var billingRule = inputDto.Adapt<BasBillingRule>();
            billingRule.Id = YitIdHelper.NextId();
            billingRule.Status = StatusEnum.Enable;
            await _basBillingRule.InsertAsync(billingRule);

            //添加计费规则详情
            var billingRuleInfos = new List<BasBillingRuleInfo>();

            //添加会员等级价格
            var billingRuleInfoMembers = new List<BasBillingRuleInfoMember>();
            foreach (var item in inputDto.BillingRuleInfos)
            {
                var data = item.Adapt<BasBillingRuleInfo>();
                data.BillingRuleId = billingRule.Id;
                data.Id = YitIdHelper.NextId();
                if (item.MemberPriceType == MemberPriceTypeEnum.Pron)
                {
                    //添加会员等级 的价格
                    billingRuleInfoMembers.AddRange(item.MemberPrice.Select(memberPrice => new BasBillingRuleInfoMember() { BasBillingRuleInfoId = data.Id, GradeId = memberPrice.GradeId, Price = memberPrice.Price, }));
                }
                billingRuleInfos.Add(data);
            }

            await _basBillingRuleInfo.InsertRangeAsync(billingRuleInfos);
            if (billingRuleInfoMembers.Count > 0)
            {

                await _basBillingRuleInfoMember.InsertRangeAsync(billingRuleInfoMembers);
            }

            return true;
        }



        /// <summary>
        /// 启用/禁用场地计费规则
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [DisplayName("启用/禁用计费规则")]
        public async Task<bool> EnableDisableBillingRule(EnableDisableBillingRuleDto inputDto)
        {
            var data = await _basSiteBillingRule.AsQueryable()
                .Where(x => inputDto.BillingRuleId == x.Id)
                .FirstAsync();
            data.Status = inputDto.Status;

            var res = await _basSiteBillingRule.UpdateAsync(data);

            return res;
        }


        /// <summary>
        /// 修改计费规则
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [UnitOfWork]
        [DisplayName("修改计费规则")]
        [ApiDescriptionSettings(Name = "UpdateBillingRule"), HttpPut]
        public async Task<bool> UpdateBillingRule(BillingRuleCreateOrUpDateDto inputDto)
        {


            //时间验证
            CheckBillingRuleTime(inputDto.BillingRuleInfos);

            var billingRule = await _basBillingRule.GetFirstAsync(x => x.Id == inputDto.Id.Value);
            if (billingRule != null)
            {
                billingRule.Sort = inputDto.Sort;
                billingRule.RuleName = inputDto.RuleName;
                await _basBillingRule.UpdateAsync(billingRule);

                //删除规则详情
                var billingRuleInfoList = await _basBillingRuleInfo.AsQueryable().Where(x => x.BillingRuleId == inputDto.Id).ToListAsync();
                await _basBillingRuleInfo.FakeDeleteAsync(billingRuleInfoList);


                //添加子订单
                var billingRuleInfos = new List<BasBillingRuleInfo>();
                //添加子订单会员等级价格
                var billingRuleInfoMembers = new List<BasBillingRuleInfoMember>();

                foreach (var item in inputDto.BillingRuleInfos)
                {
                    var data = item.Adapt<BasBillingRuleInfo>();
                    data.BillingRuleId = billingRule.Id;
                    data.Id = YitIdHelper.NextId();


                    //删除子订单会员等级价格
                    var billingRuleInfoMemberList = await _basBillingRuleInfoMember.AsQueryable()
                        .Where(x => x.BasBillingRuleInfoId == item.Id).ToListAsync();
                    await _basBillingRuleInfoMember.FakeDeleteAsync(billingRuleInfoMemberList);

                    if (item.MemberPriceType == MemberPriceTypeEnum.Pron&& item.MemberPrice!=null)
                    {
                        //添加会员等级 的价格
                        billingRuleInfoMembers.AddRange(item.MemberPrice.Select(memberPrice => new BasBillingRuleInfoMember() { BasBillingRuleInfoId = data.Id, GradeId = memberPrice.GradeId, Price = memberPrice.Price, }));
                    }
                    billingRuleInfos.Add(data);
                }

                //所有价格 重新添加
                await _basBillingRuleInfo.InsertRangeAsync(billingRuleInfos);
                if (billingRuleInfoMembers.Count > 0)
                {

                    await _basBillingRuleInfoMember.InsertRangeAsync(billingRuleInfoMembers);
                }


            }
            return true;
        }


        /// <summary>
        /// 删除规则
        /// </summary>
        /// <returns></returns>
        [UnitOfWork]
        [DisplayName("删除规则")]
        [ApiDescriptionSettings(Name = "Del"), HttpDelete]
        public async Task<bool> Del(long id)
        {

            var data = await _basBillingRule.AsQueryable().Where(x => x.Id == id).FirstAsync();
            if (data == null)
            {
                throw Oops.Oh("规则不存在");
            }
            await _basBillingRule.FakeDeleteAsync(data);

            var dataInfos = await _basBillingRuleInfo.AsQueryable().Where(x => x.BillingRuleId == id).ToListAsync();

            await _basBillingRuleInfo.FakeDeleteAsync(dataInfos);

            return true;
        }

        /// <summary>
        /// 获取计费规则列表
        /// </summary>
        /// <returns></returns>
        public async Task<List<BillingRuleDto>> GetBillingRuleList(BillingRuleListDto inputDto)
        {

            var venueId = _basSiteType.GetFirst(x => x.Id == inputDto.SiteTypeId)?.Id ?? 0;

            var data = _basBillingRule.AsQueryable()
                 .LeftJoin<BasVenues>((u, a) => u.VenueId == a.Id)
                .WhereIF(inputDto.VenueId.HasValue, (u, a) => u.VenueId == inputDto.VenueId)
                .WhereIF(inputDto.SiteTypeId.HasValue, (u, a) => u.VenueId == venueId)
                 .Select((u, a) => new BillingRuleDto()
                 {
                     Id = u.Id.SelectAll(),
                     VenueName=a.VenuesName
                 }).ToList();
            return data;
        }
        #endregion


        #region 场地积分规则

        [HttpPost]
        [DisplayName("场地计费规则 分页")]
        public async Task<SqlSugarPagedList<SiteBillingRuleDto>> SiteBillingRulePage(SiteBillingRulePageDto inputDto)
        {
            var result = await _basSiteBillingRule.AsQueryable()
                .Where(x => x.SiteId == inputDto.SiteId)
                .WhereIF(inputDto.Status.HasValue, u => u.Status == inputDto.Status)
                .Select(x => new SiteBillingRuleDto()
                {
                    Id = x.Id.SelectAll(),
                })
                .OrderBy(x => x.Sort)
                .ToPagedListAsync(inputDto.Page, inputDto.PageSize);

            return result;
        }


        /// <summary>
        /// 编辑场地类型规则
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [UnitOfWork]
        [DisplayName("编辑场地计费规则")]
        public async Task<bool> EditSiteBillingRule(EditSiteBillingRuleDto inputDto)
        {
            //查询 场地的规则
            var data = await _basSiteBillingRule.AsQueryable()
                .Where(x => inputDto.SiteIds.Contains(x.SiteId) && x.BillingRuleId == inputDto.BillingRuleId)
                .ToListAsync();

            var weeksStr = inputDto.Weeks.Aggregate("", (current, week) => current + ((int)week + ","));
            weeksStr = weeksStr.TrimEnd(',');

            //删除
            await _basBillingRuleInfo.FakeDeleteAsync(data);
            foreach (var item in inputDto.SiteIds)
            {
                //add
                await _basSiteBillingRule.InsertAsync(new BasSiteBillingRule()
                {
                    BillingRuleId = inputDto.BillingRuleId,
                    SiteId = item,
                    Sort = inputDto.Sort,
                    Weeks = $"[{weeksStr}]",
                });

            }

            return true;
        }


        /// <summary>
        /// 删除场地计费规则
        /// </summary>
        /// <returns></returns>
        [HttpDelete]
        [DisplayName("删除场地计费规则")]
        public async Task<bool> DelSiteBillingRule(long siteBillingRuleId)
        {
            var data = await _basSiteBillingRule.AsQueryable()
            .Where(x => siteBillingRuleId == x.Id)
                .ToListAsync();

            if (data.Count<=0)
            {
                throw Oops.Oh("数据不存在");
            }
            //删除
            var res = await _basBillingRuleInfo.FakeDeleteAsync(data);
            if (res<=0)
            {
                throw Oops.Oh("删除失败");
            }
            return true;
        }

        /// <summary>
        /// 启用/禁用场地计费规则
        /// </summary>
        /// <param name="inputDto"></param>
        /// <returns></returns>
        [DisplayName("启用/禁用场地计费规则")]
        public async Task<bool> EnableDisableSiteBillingRule(EnableDisableSiteBillingRuleDto inputDto)
        {
            var data = await _basSiteBillingRule.AsQueryable()
                .Where(x => inputDto.SiteBillingRuleId == x.Id)
                .FirstAsync();
            data.Status = inputDto.Status;

            var res = await _basSiteBillingRule.UpdateAsync(data);

            return res;
        }

        #endregion



        /// <summary>
        /// 场地计费规则 分页
        /// </summary>
        /// <returns></returns>


        #region 私有方法

        /// <summary>
        /// 检查计费规则时间
        /// </summary>
        public void CheckBillingRuleTime(List<BillingRuleInfoCreateOrUpDateDto> inputDto)
        {
            if (inputDto.Count<=0)
            {
                throw Oops.Oh("时间没有设置");
            }

            inputDto = inputDto.OrderBy(x => x.StartTime).ToList();

            //第一个
            var fist = inputDto.FirstOrDefault();
            if (fist.StartTime != 0)
            {
                throw Oops.Oh("开始时间应为 00 点");
            }

            //最后一个
            var last = inputDto.LastOrDefault();
            if (last.EndTime != 24)
            {
                throw Oops.Oh("结束时间应为 24 点");
            }

            var lastTime = 0;
            foreach (var item in inputDto)
            {
                if (lastTime != item.StartTime)
                {
                    throw Oops.Oh($"{lastTime}点_{item.StartTime}点 没有连贯");
                }

                lastTime = item.EndTime;
            }



        }
        #endregion
    }
}
